package network;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import model.GameConstants;
import ctf.Log;
import ctf.network.ProtocolError;
import ctf.network.SocketClosedException;
import ctf.network.UninitializedSocketException;
import ctf.network.tcp.Connection;
import ctf.network.tcp.ConnectionOwner;
import ctf.network.tcp.Server;
import ctf.network.tcp.ServerOwner;
/**
 * Class responsible for managing the network connection.
 * @author N. Bhatia, A. Butt, N. Evans, C. Levesque, P. OKeefe
 *
 */
public class NetworkAdapter implements INetworkAdapter, ServerOwner, ConnectionOwner {

	private Server server;
	private List<Connection> connectionList;
	private IMessageListener messageListener;

	/**
	 * Class for managing the interaction between network and simulator classes.
	 * @param numberOfClients Number of connections the server will accept.
	 * @param messageListener The instance of the IMessageListener.
	 * @throws UnknownHostException
	 * @throws IOException
	 * @throws UninitializedSocketException
	 */
	public NetworkAdapter(int numberOfClients, IMessageListener messageListener)
			throws UnknownHostException, IOException,
			UninitializedSocketException {
		connectionList = new ArrayList<Connection>();
		this.messageListener = messageListener;
		this.init();
	}

	@Override
	public void connectionAccepted(Connection client) {
		int clientId = connectionList.size();
		Log.getInstance().println("Accepted client#"+clientId+"  {" + client.toString() + "}");
		connectionList.add(client);
		client.setOwner(this);
		client.start();
		messageListener.registerClient(clientId);
	}

	@Override
	public void connectionClosed(Connection client) {
		Log.getInstance().println("Closed {" + client.toString() + "}");
		this.connectionList.remove(client);
		if (connectionList.size() == 0) {
			this.messageListener.resetListener();
		}
	}

	@Override
	public void lineReceived(String line, Connection client) {
		try {
			messageListener.messageReceived(connectionList.indexOf(client),
					line);
		} catch (ProtocolError e) {
			Log.getInstance().println("************************************");
			Log.getInstance().println(
					"Protocol Error caused by " + client.toString());
			Log.getInstance().println(e.getMessage());
			Log.getInstance().println("Ending game and notifying clients");
			Log.getInstance().println("************************************");
			try {
				client.sendLine("error: {"
						+ e.getMessage().substring(0,
								Math.min(e.getMessage().length(), 255)));
				for (int i = 0; i < this.connectionList.size(); i++) {
					connectionList.get(i).sendLine(
							"error: STEAL Error detected. Game ending.");
				}
			} catch (SocketClosedException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			} catch (UninitializedSocketException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			} catch (IOException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			}

		}

	}

	@Override
	public void sendMessage(String message, int clientID)
			throws SocketClosedException, UninitializedSocketException,
			IOException {
		connectionList.get(clientID).sendLine(message);
	}
	
	@Override
	public void reset()
	{
		this.connectionList.clear();
		this.init();
	}
	
	/**
	 * Initializes the required network components, such as port.
	 */
	private void init()
	{
		server = new Server(this);
		try {
			this.server.bind(GameConstants.SERVER_PORT);
			this.server.startAccepting(2);
			Log.getInstance().println("Network initialized. Waiting for 2 connections.");
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UninitializedSocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}
